package com.zst.amqp.utils;

import com.zst.amqp.annotation.Consumer;
import com.zst.amqp.entity.ConsumerInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

/**
 * 扫描使用了Consumer注解的bean的工具类
 */
public class ConsumerScanUtil {
    private static final Logger logger = LoggerFactory.getLogger(ConsumerScanUtil.class);

    public static List<ConsumerInfo> scan(ApplicationContext context, String basePackage) {
        if (StringUtils.isEmpty(basePackage)) {
            return Collections.emptyList();
        }

        ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
        provider.addIncludeFilter(new AnnotationTypeFilter(Component.class));
        Set<BeanDefinition> beanDefinitionSet = provider.findCandidateComponents(basePackage);
        Iterator<BeanDefinition> i = beanDefinitionSet.iterator();

        List<ConsumerInfo> consumerInfos = new ArrayList<>();
        while (i.hasNext()) {
            BeanDefinition bd = i.next();
            try {
                consumerInfos.addAll(listenerMethodScan(context, Class.forName(bd.getBeanClassName())));
            } catch (ClassNotFoundException e) {
                logger.error(e.getMessage(), e);
            }
        }

        return consumerInfos;
    }

    /**
     * 扫描类里使用了Consumer注解的方法
     * @param context
     * @param beanClass
     * @return
     */
    private static List<ConsumerInfo> listenerMethodScan(ApplicationContext context, Class beanClass) {
        List<ConsumerInfo> list = new ArrayList<>();
        Method[] methods = beanClass.getMethods();
        for (Method m : methods) {
            //从Object类里继承过来的方法，即使使用了注解也不会去处理
            if (m.getAnnotation(Consumer.class) != null && !isObjectMethod(m)) {
                Consumer consumer = m.getAnnotation(Consumer.class);
                ConsumerInfo consumerInfo = new ConsumerInfo();
                consumerInfo.setConsumerClass(beanClass);
                consumerInfo.setMethodName(m.getName());
                consumerInfo.setMsgType(consumer.msgType());
                list.add(consumerInfo);
            }
        }

        return list;
    }

    /**
     * 判断方法是否Object类里的方法（这个是否有必要）
     * @param method
     * @return
     */
    private static boolean isObjectMethod(Method method) {
        Method[] methods = Object.class.getMethods();
        for (Method m : methods) {
            if (m.equals(method)) {
                return true;
            }
        }

        return false;
    }
}
